#include "stdafx.h"
#include <LitString.h>

const Lit::String::char_type Lit::String::WhiteSpace(' ');

#ifdef LIT_UNICODE
LIT_API std::wostream& operator<<( std::wostream& strm, const Lit::String &str ){ strm << str.data(); return strm; }
#else
LIT_API std::ostream& operator<<( std::ostream& strm, const Lit::String &str ){ strm << str.data(); return strm; }
#endif

LIT_API Lit::String operator+( const Lit::String::char_type* str, const Lit::String& str2 )
{
	return Lit::String( str ) + str2;
}

namespace Lit
{
	class LIT_API StringPrivates
	{
		friend class LIT_API String;
		friend class LIT_API StringVector;
		friend class LIT_API StringVectorPrivates;
		friend class LIT_API StringIterPrivates;
		friend class LIT_API StringConstIterPrivates;
#ifdef LIT_UNICODE
		typedef std::wstring				Traits;
		typedef Traits::traits_type			CharTraits;
#else
		typedef std::string					Traits;
		typedef Traits::traits_type			CharTraits;
#endif

		Traits mData;
	public:
		StringPrivates( ) : mData( ){}
		StringPrivates( const size_t count, const CharTraits::char_type fill = ' ' ) : mData( count, fill ){}
		StringPrivates( const CharTraits::char_type* str ) : mData( str ){}
		StringPrivates( const Traits &data ) : mData( data ){}
		StringPrivates( const StringPrivates& rk ):mData(rk.mData){}
		~StringPrivates(){}
		
		Traits& data(){ return mData; }
		const Traits& data() const{ return mData; }
		
		Traits* operator->(){ return &mData; }
		const Traits* operator->() const{ return &mData; }

		StringPrivates& operator=( const Traits& rk ){ mData=rk; return *this; }
		StringPrivates& operator=( const CharTraits::char_type* rk ){ mData=rk; return *this; }
		StringPrivates& operator=( const StringPrivates& rk ){ mData=rk.mData; return *this; }
	};
	class LIT_API StringIterPrivates
	{
		friend class LIT_API String;
		friend class LIT_API StringPrivates;
		friend class LIT_API StringIter;
	public:
		typedef StringPrivates::Traits::iterator IterType;

		StringIterPrivates( ){}
		StringIterPrivates( const IterType & rk ) : iter(rk){}
		StringIterPrivates( const String& str, const size_t offset_ = 0 ){ iter = (str.mPrivates->mData.begin() + offset_); }
		StringIterPrivates( const StringIterPrivates& rk ){ iter = rk.iter; }
		~StringIterPrivates(){ }
		
		bool operator==( const IterType & rk ) const{ return iter == rk; }
		bool operator!=( const IterType& rk ) const{ return iter == rk; }

		StringIterPrivates& operator=( const StringIterPrivates& rk ){ iter = rk.iter; return *this; }
		
	protected:
		IterType iter;
	};

	class LIT_API StringConstIterPrivates
	{
		friend class LIT_API String;
		friend class LIT_API StringPrivates;
		friend class LIT_API StringConstIter;
	public:
		typedef StringPrivates::Traits::const_iterator IterType;
		
		StringConstIterPrivates( ){}
		StringConstIterPrivates( const IterType & rk ) : iter(rk){}
		StringConstIterPrivates( const String& str, const size_t offset_ = 0 ){ iter = (str.mPrivates->mData.begin() + offset_); }
		StringConstIterPrivates( const StringConstIterPrivates& rk ){ iter = rk.iter; }
		~StringConstIterPrivates(){ }
		
		bool operator==( const IterType & rk ) const{ return iter == rk; }
		bool operator!=( const IterType& rk ) const{ return iter == rk; }

		StringConstIterPrivates& operator=( const StringConstIterPrivates& rk ){ iter = rk.iter; return *this; }
		
	private:
		IterType iter;
	};

	StringIter::StringIter( ){ mPrivates = nullptr; _alloc( ); }
	StringIter::StringIter( const String& str, const size_t offset ){ mPrivates = nullptr; _alloc( offset, str ); }
	StringIter::StringIter( const StringIter& rk ){ mPrivates = nullptr; _alloc( rk ); }
	StringIter::~StringIter(){ _dealloc(); }

	StringIter& StringIter::operator=( const StringIter& rk ){ _alloc( rk ); return *this; }
	
	bool StringIter::operator==( const StringIter & rk ) const{ return mPrivates->iter == rk.mPrivates->iter; }
	bool StringIter::operator!=( const StringIter& rk ) const{ return mPrivates->iter != rk.mPrivates->iter; }
	void StringIter::_alloc(){ _dealloc(); mPrivates = new StringIterPrivates; }
	void StringIter::_alloc( const StringIter& rk ){ _dealloc(); mPrivates = new StringIterPrivates(*rk.mPrivates); }
	void StringIter::_alloc( const size_t pos, const String& str ){ _dealloc(); mPrivates = new StringIterPrivates(str, pos); }
	void StringIter::_dealloc(){ if( mPrivates != nullptr ) delete mPrivates, mPrivates = nullptr; }

	StringConstIter::StringConstIter( ){ mPrivates = nullptr; _alloc( ); }
	StringConstIter::StringConstIter( const String& str, const size_t offset ){ mPrivates = nullptr; _alloc( offset, str ); }
	StringConstIter::StringConstIter( const StringConstIter& rk ){ mPrivates = nullptr; _alloc( rk ); }
	StringConstIter::~StringConstIter(){ _dealloc(); }

	StringConstIter& StringConstIter::operator=( const StringConstIter& rk ){ _alloc( rk ); return *this; }
	bool StringConstIter::operator==( const StringConstIter & rk ) const{ return mPrivates->iter == rk.mPrivates->iter; }
	bool StringConstIter::operator!=( const StringConstIter& rk ) const{ return mPrivates->iter != rk.mPrivates->iter; }

	void StringConstIter::_alloc(){ _dealloc(); mPrivates = new StringConstIterPrivates; }
	void StringConstIter::_alloc( const StringConstIter& rk ){ _dealloc(); mPrivates = new StringConstIterPrivates(*rk.mPrivates); }
	void StringConstIter::_alloc( const size_t pos, const String& str ){ _dealloc(); mPrivates = new StringConstIterPrivates(str, pos); }
	void StringConstIter::_dealloc(){ if( mPrivates != nullptr ) delete mPrivates, mPrivates = nullptr; }

	
	const size_t String::npos(StringPrivates::Traits::npos);
	
	
#ifdef LIT_OGRE_SUPPORT
	String::String( const Ogre::String & str ){ mPrivates = nullptr; _alloc( str.c_str() ); }
#endif
	String::String( ) { mPrivates = nullptr; _alloc( ); }
	String::String( const char_type elem ){ mPrivates = nullptr; _alloc( 1, elem ); }
	String::String( const size_t count, const char_type fill ){ mPrivates = nullptr; _alloc( count, fill ); }
	String::String( const char_type* str ) { mPrivates = nullptr; _alloc( str );  }
	String::String( const String& rk ){ mPrivates = nullptr; _copy( *rk.mPrivates ); }
	String::~String( ){ _desalloc(); }
		
#ifdef LIT_OGRE_SUPPORT
	String::operator Ogre::String() const
	{
		return Ogre::String( data() );
	}
#endif

	String::iterator String::begin(){
		return iterator( *this, 0 );
	}
	String::iterator String::end(){
		return iterator( *this, size() );
	}
	String::const_iterator String::begin() const{
		return const_iterator( *this, 0 );
	}
	String::const_iterator String::end() const{
		return const_iterator( *this, size() );
	}

	size_t String::hash() const
	{
		return std::hash<std::string>()(mPrivates->mData);
	}
	size_t String::find( const String &str ) const{
		return mPrivates->mData.find( str.data() );
	}
	size_t String::rfind( const String &str ) const{
		return mPrivates->mData.rfind( str.data() );
	}
	
	size_t String::resize( size_t sz ){
		size_t old = size();
		mPrivates->mData.resize( sz );
		return old;
	}

	size_t String::resize( size_t sz, String::char_type ch )
	{
		size_t old = size();
		mPrivates->mData.resize( sz, ch );
		return old;
	}

	size_t String::reserve( size_t sz ){
		size_t old = capacity();
		mPrivates->mData.reserve( sz );
		return old;
	}
	size_t String::capacity() const
	{
		return mPrivates->mData.capacity();
	}
	
	String::char_type& String::operator[]( const size_t id )
	{
		return mPrivates->mData.at(id);
	}
	
	String& String::operator()( const String &rk ){ mPrivates->mData += rk.mPrivates->mData; return *this; }
	String& String::operator()( const char_type* rk ){ mPrivates->mData += rk; return *this; }
	String& String::operator()( const char_type rk ){ mPrivates->mData += rk; return *this; }
	String& String::operator<<( const String &rk ){ mPrivates->mData += rk.mPrivates->mData; return *this; }
	String& String::operator<<( const char_type* rk ){ mPrivates->mData += rk; return *this; }
	String& String::operator<<( const char_type rk ){ mPrivates->mData += rk; return *this; }
	bool String::operator==( const String::char_type *rk ) const{ return (mPrivates->mData == StringPrivates::Traits(rk)); }
	const String::char_type* String::data() const{ return mPrivates->mData.c_str(); }
	String& String::operator=( const String::char_type* str ){ _alloc( str ); return *this; }
	
	StringPrivates* String::_alloc(){ 
		if( mPrivates ) return mPrivates; 
		mPrivates = new StringPrivates; 
		return mPrivates; 
	}
	StringPrivates* String::_alloc( const String::char_type* str ){ 
		if( mPrivates ){
			mPrivates->mData = str;
			return mPrivates; 
		}
		mPrivates = new StringPrivates( str ); 
		return mPrivates; 
	}
	StringPrivates* String::_alloc( const size_t count, const String::char_type fill ){ 
		if( mPrivates ){
			mPrivates->mData.resize( count, fill );
			return mPrivates; 
		}
		mPrivates = new StringPrivates( count, fill ); 
		return mPrivates; 
	}
	StringPrivates* String::_copy( const StringPrivates &rk ){ 
		if( mPrivates ){
			(*mPrivates) = rk;
			return mPrivates; 
		}
		mPrivates = new StringPrivates( rk ); 
		return mPrivates; 
	}
	StringPrivates* String::_desalloc(){ 
		if( mPrivates ) delete mPrivates, mPrivates = nullptr; 
		return mPrivates; 
	}

	bool String::operator==( const String &rk ) const{ return (mPrivates->mData == rk.mPrivates->mData); }
	String& String::operator=( const String& rk ){ _copy( *rk.mPrivates );return *this; }
	
	size_t String::size() const{ return mPrivates->mData.size(); }
	String String::substr( const size_t offset, const size_t count ) const{
		if( (offset+count) >= size() ) 
			throw std::out_of_range( "Offset " + std::to_string( offset ) + " out of range for String !" );
		return String(mPrivates->mData.substr( offset, count  ).c_str());
	}
	
	bool String::operator!=( const String &rk ) const{
		return (mPrivates->mData != rk.mPrivates->mData);
	}

	bool String::operator!=( const String::char_type* rk ) const{return (mPrivates->mData != StringPrivates::Traits(rk)); }

	bool String::matches( const String &rk, bool case_sensitive ) const
	{
		String	a( trimmed() ), 
				b( trimmed() );
		if( !case_sensitive )
		{
			a=a.toLower();
			b=b.toLower();
		}
		return a==b;
	}
	String String::toLower() const
	{
		String ret(*this);
		for( StringPrivates::Traits::iterator i=mPrivates->mData.begin(); i!=mPrivates->mData.end(); i++ )
			*i = toupper( *i );
		return ret;
	}
	String String::toUpper() const
	{
		String ret(*this);
		for( StringPrivates::Traits::iterator i=mPrivates->mData.begin(); i!=mPrivates->mData.end(); i++ )
			*i = tolower( *i );
		return ret;
	}
	String String::trimmed( char_type trimmed_char ) const{
		String ret( *this );
		return ret.trim();
	}
	String& String::trim( char_type trimmed_char ){
		while( !empty() && ((*mPrivates->mData.begin()) == trimmed_char) ) mPrivates->mData.erase( mPrivates->mData.begin() );
		while( !empty() && (mPrivates->mData.at( mPrivates->mData.size() -1 ) == trimmed_char) ) mPrivates->mData.erase( mPrivates->mData.size() -1 );
		return *this;
	}
	String& String::replaceAll( const String &what, const String &by_what, bool case_sensitive ){
		if( empty() || what.empty() )  return *this;
		size_t p;
		String wwhat(case_sensitive?what:what.toLower());
		String bwhat(case_sensitive?by_what:by_what.toLower());
		while( ((p=mPrivates->mData.find( wwhat.data() )) != npos ) )
		{
			mPrivates->mData = mPrivates->mData.replace( p, wwhat.size(), bwhat.data() );
		}
		return *this;
	}
	String String::replaceAll( const String &what, const String &by_what, bool case_sensitive ) const{
		size_t p;
		String wwhat(case_sensitive?what:what.toLower());
		String bwhat(case_sensitive?what:what.toLower());
		String result( *this );
		while( ((p=result.mPrivates->mData.find( wwhat.data() )) != npos ) )
		{
			result.mPrivates->mData = result.mPrivates->mData.replace( p, wwhat.size(), bwhat.data() );
		}
		return result;
	}
	
	String& String::operator+=( const char_type rk ){ mPrivates->mData += rk; return *this; }
	String String::operator+( const char_type rk ) const{ String ret(*this); return ret+String(rk); }
		
	String& String::operator+=( const String &rk ){ mPrivates->mData += rk.mPrivates->mData; return *this; }
	String String::operator+( const String &rk ) const{ mPrivates->mData += rk.mPrivates->mData; return *this; }

	String& String::operator+=( const char_type* rk ){ mPrivates->mData+=rk; return *this; }
	String String::operator+( const char_type* rk ) const{ StringPrivates::Traits ret( mPrivates->mData ); ret += StringPrivates::Traits(rk); return String(ret.c_str()); }

	void String::erase( const size_t offset, const size_t count )
	{
		mPrivates->mData.erase( offset, count );
	}

	String::char_type& String::at( const size_t id ){ if( id >= size() ) throw std::out_of_range( "Id " + std::to_string( id ) + " out of range for String !" ); return mPrivates->mData.at(id); }
	const String::char_type& String::at( const size_t id ) const{ if( id >= size() ) throw std::out_of_range( "Id " + std::to_string( id ) + " out of range for String !" ); return mPrivates->mData.at(id); }

	bool String::empty() const{ return mPrivates->mData.empty(); }
	void String::clear() const{ return mPrivates->mData.clear(); }

	StringVector String::split( const String &delim ) const
	{
		size_t i=0, old=0;
		StringVector vec;
		while( (i = mPrivates->mData.find( delim.mPrivates->mData, i )) != StringPrivates::Traits::npos )
		{
			StringPrivates::Traits& d(mPrivates->mData);
			vec.push_back( String(d.substr( old, i-old ).c_str()) );
			old = i;
		}
		return vec;
	}

	class LIT_API StringVectorPrivates
	{
		typedef StringPrivates::Traits	StringTraits;
		typedef std::vector<String>		Traits;

		friend class LIT_API StringVector;
	public:
		StringVectorPrivates(){}
		StringVectorPrivates( const StringVectorPrivates&e ):vec(e.vec){}
		~StringVectorPrivates(){}

		StringVectorPrivates& operator=( const StringVectorPrivates& e ){ vec.assign( e.vec.begin(), e.vec.end() ); return *this; }

	private:
		Traits vec;
	};
	const size_t StringVector::npos(StringPrivates::Traits::npos);

	StringVector::StringVector( )
		: mPrivates( new StringVectorPrivates )
	{}
	StringVector::StringVector( const StringVector& e )
		: mPrivates( new StringVectorPrivates( *e.mPrivates ) )
	{}
	StringVector::~StringVector( )
	{
		if( mPrivates != nullptr )
		{
			delete mPrivates;
			mPrivates = nullptr;
		}
	}
	StringVector& StringVector::operator=( const StringVector& vec ){
		if( mPrivates )
			delete mPrivates, mPrivates = nullptr;
		mPrivates = new StringVectorPrivates( *vec.mPrivates );
		return *this;
	}
	StringVector& StringVector::push_back( const String & rk )
	{
		mPrivates->vec.push_back( rk );
		return *this;
	}
	
	StringVector& StringVector::operator << ( const String & rk ){ return push_back( rk ); }

	size_t StringVector::size() const{ return mPrivates->vec.size(); }
	void StringVector::clear(){ mPrivates->vec.clear(); }
	bool StringVector::empty() const{ return mPrivates->vec.empty(); }
		
	String& StringVector::at( const size_t id ){ return mPrivates->vec.at(id); }
	const String& StringVector::at( const size_t id ) const{ return mPrivates->vec.at(id); }

	bool StringVector::has( const String &str ) const{ 
		for( auto i=mPrivates->vec.begin(); i!=mPrivates->vec.end(); i++ )
			if( (*i) == str ) return true;
		return false;
	}
	
	void StringVector::erase( const size_t offset, const size_t count )
	{
		if( offset + count >= size() )
			throw std::out_of_range( "["+std::to_string(offset)+":"+std::to_string(offset+count)+"] Index out of range in StringVector" );

		mPrivates->vec.erase( mPrivates->vec.begin()+offset, mPrivates->vec.begin()+(offset+count) );
	}
	/** Finds a string
		\return The absolute position or StringVector::npos
	*/
	size_t StringVector::find( const String &str ) const{ 
		StringPrivates::Traits& sstr(str.mPrivates->mData);
		size_t id = 0;
		for( auto i=mPrivates->vec.begin(); i!=mPrivates->vec.end(); i++ )
		{
			if( i->mPrivates->mData == sstr ) return id;
			id++;
		}
		return npos;
	}


	/** Reverse finds a string
		\return The absolute position or StringVector::npos
	*/
	size_t StringVector::rfind( const String &str ) const{ 
		StringPrivates::Traits& sstr(str.mPrivates->mData);
		size_t id = mPrivates->vec.size();
		for( auto i=mPrivates->vec.rbegin(); i!=mPrivates->vec.rend(); i++ )
		{
			if( i->mPrivates->mData == sstr ) return id;
			id--;
		}
		return npos;
	}
};


namespace Lit
{
	
};